package dao;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

//通过这个类来封装针对file_meta表的操作
public class FileDao {
    //1.初始化数据库（建表
    public void initDB(){
        //1.先能够读取到db.sql中的sql语句
        //2.根据sql语句调用jdbc执行操作
        Connection connection = null;
        Statement statement = null;
        try {
            connection = DBUtil.getConnection();
            statement = connection.createStatement();
            String[] sqls = getInitSQL();
            for (String sql :sqls){
                System.out.println("[initDB] sql:"+sql);
                statement.executeUpdate(sql);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,null);
        }
    }
    // 从db.sql中读取文件内容
    //虽然当前db.sql中只有一个SQL语句，但是原则上写了多个也是要支持的
    //返回值就设定称一个String[] ，每一个元素都是一个独立的SQL语句
    private String[] getInitSQL(){
        //此时需要能够动态获取到db.sql文件的路径，而不要直接写死一个绝对路径
        StringBuilder stringBuilder = new StringBuilder();//用来存储最终的结果
        try(InputStream inputStream = FileDao.class.getClassLoader().getResourceAsStream("db.sql")){
           try (InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"utf8")){
               while (true){
                   //此处的ch返回值虽然是int 但实际上是个char
                   //只不过为了表示-1这个特殊的结束标记，使用int类型作为返回值
                   int ch = inputStreamReader.read();
                   if (ch == -1){
                       //文件读取完毕
                       break;
                   }
                   stringBuilder.append((char)ch);
               }
           }
        }catch (IOException e){
            e.printStackTrace();
        }
        return stringBuilder.toString().split(";");
    }

    //2.插入文件/目录数据到数据库中
    public void add(List<FileMeta> fileMetas){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        //批量插入
        try {
            connection = DBUtil.getConnection();
            //关闭连接的自动提交
            connection.setAutoCommit(false);
            String sql = "insert into file_meta values(null,?,?,?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            for (FileMeta fileMeta : fileMetas){
                //针对当前FileMeta对象，替换到SQL语句中，把？替换成具体数值
                preparedStatement.setString(1,fileMeta.getName());
                preparedStatement.setString(2,fileMeta.getPath());
                preparedStatement.setBoolean(3,fileMeta.isDirectory());
                preparedStatement.setString(4,fileMeta.getPinyin());
                preparedStatement.setString(5,fileMeta.getPinyinFirst());
                preparedStatement.setLong(6,fileMeta.getSize());
                preparedStatement.setTimestamp(7,new Timestamp(fileMeta.getLastModified()) );
                //使用addBatch，把这个构造好的片段累计起来。
                // addBatch会把已经构造好的SQL保存好，同时又会允许重新构造一个新的sql出来。
                preparedStatement.addBatch();
                System.out.println("[insert] 插入文件: " + fileMeta.getPath() + File.separator + fileMeta.getName());
            }
            //执行所有的sql片段
            preparedStatement.executeBatch();
            //执行完毕后，通过commit告知数据库，添加完毕
            connection.commit();
        } catch (SQLException e) {
            //上述代码出现异常进行回滚
            try {
                if (connection != null){
                    connection.rollback();
                }

            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            DBUtil.close(connection,preparedStatement,null);
        }
    }



    //3.按照一个特定的关键词进行查询
    //在实现文件搜索功能的时候，必备的部分。
    //这个关键字可能是 文件名的一部分，也可能是文件名拼音的一部分，还可能是拼音首字母的一部分
    public List<FileMeta> searchByPattern(String pattern){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        List<FileMeta> fileMetas = new ArrayList<>();
        try {
            connection = DBUtil.getConnection();
            String sql = "select name, path, is_directory, size, last_modified from file_meta"
                    + " where name like ? or pinyin like ? or pinyin_first like ?"
                    + " order by path, name";
            statement = connection.prepareStatement(sql);
            statement.setString(1,"%"+pattern+"%");
            statement.setString(2,"%"+pattern+"%");
            statement.setString(3,"%"+pattern+"%");
            resultSet = statement.executeQuery();
            while (resultSet.next()){
                String name = resultSet.getString("name");
                String path = resultSet.getString("path");
                boolean isDirectory = resultSet.getBoolean("is_directory");
                long size = resultSet.getLong("size");
                Timestamp lastModified = resultSet.getTimestamp("last_modified");
                FileMeta fileMeta = new FileMeta(name,path,isDirectory,size,lastModified.getTime());
                fileMetas.add(fileMeta);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return fileMetas;
    }




    //4.查询  给定一个路径，查询这个路径下对应的结果（这个路径下有哪些结果
    //会在后续 重新扫描，更新数据库中用到
    public List<FileMeta> searchByPath(String targetPath){
        Connection connection = null;
        PreparedStatement statement =null;
        ResultSet resultSet = null;
        List<FileMeta> fileMetas = new ArrayList<>();
        try {
            connection = DBUtil.getConnection();
            String sql = "select name,path,is_directory,size,last_modified from file_meta " +
                    "where path = ? ";
            statement = connection.prepareStatement(sql);
            statement.setString(1,targetPath);
            resultSet = statement.executeQuery();
            while (resultSet.next()){
                String name = resultSet.getString("name");
                String path = resultSet.getString("path");
                boolean isDirectory = resultSet.getBoolean("is_directory");
                long size = resultSet.getLong("size");
                Timestamp lastModified = resultSet.getTimestamp("last_modified");
                FileMeta fileMeta = new FileMeta(name,path,isDirectory,size,lastModified.getTime());
                fileMetas.add(fileMeta);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return fileMetas;
    }




    //5.删除数据
    // 发现某个文件已经从磁盘上删掉了，此时就要把表里的内容进行一个更新
    //进行删除的时候，可能当前被删除的是一个普通文件（直接删除对应的表记录就行）
    //也有可能删除的时候，被删除的是一个目录，此时就需要把目录里包含的子文件/子目录也都一起删除
    public void delete(List<FileMeta> fileMetas){
        Connection connection = null;
        PreparedStatement statement =null;
        try {
            connection = DBUtil.getConnection();
            connection.setAutoCommit(false);

            //删除的是普通文件  删除的是目录
            for (FileMeta fileMeta:fileMetas){
                String sql = null;
                if (fileMeta.isDirectory()){
                    //针对普通文件的删除
                    sql = "delete from file_meta where name=? and path=?";
                }else {
                    //针对目录的删除  如果此处要删除的是d:/test
                    //此处的path like ?要进行替换 替换成形如 ‘d:/test%’
                    sql = "delete from file_meta where (name=? and path=?) or (path like ?)";
                }
                statement = connection.prepareStatement(sql);
                //不能使用addBatch 它的前提是sql是一个模板，而此时的sql是不一定相同的
                if (!fileMeta.isDirectory()){
                    //普通文件需要替换两个？
                    statement.setString(1,fileMeta.getName());
                    statement.setString(2,fileMeta.getPath());
                }else {
                    //针对目录的替换，需要替换三个？
                    statement.setString(1,fileMeta.getName());
                    statement.setString(2,fileMeta.getPath());
                    statement.setString(3,fileMeta.getPath()+ File.separator+fileMeta.getName()+File.separator+"%");
                }
                //开始执行删除语句
                statement.executeUpdate();
                System.out.println("[delete]"+fileMeta.getPath()+fileMeta.getName());
                statement.close();//此处代码中有多个statement对象
            }
            //高数数据库，事务执行完毕
            connection.commit();;
        } catch (SQLException e) {
            try {
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            DBUtil.close(connection,statement,null);
        }
    }
}
